#include "mainwindow.h"
#include "qjsondocument.h"
#include "qjsonobject.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("Server");
    initServer();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initServer(){
    server = new QTcpServer(this);
    //通过改造ui可实现地址和端口的自定义
    QString address_text = "127.0.0.1";
    unsigned short port = 3240;
    server->listen(QHostAddress(address_text), port);
    flag = false;
    updateState();

    //此处为核心收发区
    connect(server,&QTcpServer::newConnection,this,[this]{
        //如果有新的连接就取出
        while(server->hasPendingConnections())
        {
            //nextPendingConnection返回下一个挂起的连接作为已连接的QTcpSocket对象
            //套接字是作为服务器的子级创建的，这意味着销毁QTcpServer对象时会自动删除该套接字。
            QTcpSocket *socket=server->nextPendingConnection();
            clientList.append(socket);
            ui->LogText->append(QString("[%1:%2] Soket Connected")
                                    .arg(socket->peerAddress().toString())
                                    .arg(socket->peerPort()));

            //关联相关操作的信号槽
            //收到数据，触发readyRead



            connect(socket,&QTcpSocket::readyRead,[this,socket]{
                if(socket->bytesAvailable()<=0)
                    return;
                QByteArray jsonBytes;
                jsonBytes.append(socket->readAll());
                //分割数据流并分别处理，避免粘包
                QList<QByteArray>subarrays = jsonBytes.split('^');
                subarrays.removeLast();
                QList<QByteArray>::iterator it1 = subarrays.begin();
                for(; it1!=(subarrays.end()); ++it1)
                {
                    //QJsonParseError error;
                    QJsonDocument doc = QJsonDocument::fromJson(*it1);
                    QJsonObject recv_obj = doc.object();
                    //ui->LogText->append(error.errorString());
                    ui->LogText->append(QString("[%1:%2]")
                                            .arg(socket->peerAddress().toString())
                                            .arg(socket->peerPort()));
                    ui->LogText->append(recv_obj.value("msg").toString());
                    //当只有一人加入房间时，且接受的是选边信息，立起flag表明植物方已选择，并向房间中所有玩家广播
                    if(clientList.size() == 1 && recv_obj.value("control").toInt() == 3){
                        flag = true;
                        for(QTcpSocket *socket:qAsConst(clientList))
                        {
                            socket->write(doc.toJson().append('^'));
                        }
                    }
                    //当植物方已选择时，将第二个接受的选边信息json值中select改为false
                    //并向所有玩家广播
                    else if(flag == true && recv_obj.value("control").toInt() == 3){
                        recv_obj.remove("select");
                        recv_obj.insert("select", false);
                        QJsonDocument temp_doc = QJsonDocument(recv_obj);
                        for(QTcpSocket *socket:qAsConst(clientList))
                        {
                            socket->write(temp_doc.toJson().append('^'));
                        }

                        QJsonObject sendObj = {
                            {"control", 4},
                            {"msg", NULL},
                            {"username",NULL},
                            {"select", NULL},
                            {"xpos",NULL},{"ypos",NULL},
                            {"type", NULL}
                        };
                        QJsonDocument document=QJsonDocument(sendObj);
                        for(QTcpSocket *socket:qAsConst(clientList))
                        {
                            socket->write(document.toJson().append('^'));
                        }

                    }
                    //当接受非选边信息时，维持原样向所有玩家广播
                    else{
                        for(QTcpSocket *socket:qAsConst(clientList))
                        {
                            socket->write(doc.toJson().append('^'));
                        }
                    }
                }

            });

#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
            //错误信息
            connect(socket, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
                    [this,socket](QAbstractSocket::SocketError){
                        ui->textRecv->append(QString("[%1:%2] Soket Error:%3")
                                                 .arg(socket->peerAddress().toString())
                                                 .arg(socket->peerPort())
                                                 .arg(socket->errorString()));
                    });
#else \
                //错误信息
                connect(socket,&QAbstractSocket::errorOccurred,[this,socket](QAbstractSocket::SocketError){
                    ui->LogText->append(QString("[%1:%2] Soket Error:%3")
                                            .arg(socket->peerAddress().toString())
                                            .arg(socket->peerPort())
                                            .arg(socket->errorString()));
                });
#endif

            //连接断开，销毁socket对象，这是为了开关server时socket正确释放
            connect(socket,&QTcpSocket::disconnected,[this,socket]{
                socket->deleteLater();
                clientList.removeOne(socket);
                ui->LogText->append(QString("[%1:%2] Soket Disonnected")
                                         .arg(socket->peerAddress().toString())
                                         .arg(socket->peerPort()));
                updateState();
            });
        }
        updateState();
    });
    connect(ui->sendButton,&QPushButton::clicked,[this]{
        //判断是否开启了server
        if(!server->isListening())
            return;
        //将发送区文本发送给客户端
        const QByteArray send_data=ui->SendText->toPlainText().toUtf8();
        //数据为空就返回
        if(send_data.isEmpty())
            return;
        for(QTcpSocket *socket:qAsConst(clientList))
        {
            socket->write(send_data);
            //socket->waitForBytesWritten();
        }
    });
    updateState();
}


void MainWindow::updateState(){
    if(server->isListening()){
        setWindowTitle(QString("Server[%1:%2] connections:%3")
                           .arg(server->serverAddress().toString())
                           .arg(server->serverPort())
                           .arg(clientList.count()));
    }else{
        setWindowTitle("Server");
    }
}
